﻿// librtsp.cpp : 定义 DLL 的导出函数。
//

#include "pch.h"
#include "framework.h"
#include "librtsp.h"
#include "rtspplay.h"

static std::mutex dll_mutex;
static LPTOP_LEVEL_EXCEPTION_FILTER gPreviousFilter = NULL;

static LONG WINAPI MiniDumpUnhandledExceptionFilter(CONST PEXCEPTION_POINTERS pExceptionInfo)
{
	std::string filename = "librtspdump_" + std::to_string(GetCurrentProcessId()) + ".dmp";

	HANDLE lhDumpFile = CreateFileA(filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	MINIDUMP_EXCEPTION_INFORMATION loExceptionInfo;
	loExceptionInfo.ExceptionPointers = pExceptionInfo;
	loExceptionInfo.ThreadId = GetCurrentThreadId();
	loExceptionInfo.ClientPointers = TRUE;

	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), lhDumpFile, MiniDumpNormal, &loExceptionInfo, NULL, NULL);

	CloseHandle(lhDumpFile);

	if (gPreviousFilter != NULL)
		return gPreviousFilter(pExceptionInfo);
	else
		return EXCEPTION_CONTINUE_SEARCH;
}

void rtsp_enable_console_log()
{
	g_Logger.EnableConsole();
}

void rtsp_pixel_format(int type)
{
	CRtspPlay::SetVideoDecodeType(type);
}

void rtsp_hw_support(int value)
{
	CRtspPlay::SetSupportHW(value);
}
void rtsp_init()
{
	spdlog::info(__FUNCTION__);
	std::lock_guard<std::mutex> autolock(dll_mutex);
	if (gPreviousFilter == nullptr)
	{
		SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
		gPreviousFilter = SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER(MiniDumpUnhandledExceptionFilter));
		spdlog::info(__FUNCTION__" 注册dll dump生成");
	}
	spdlog::info("ffmpeg version:{}", av_version_info());
	AVHWDeviceType device_type = AVHWDeviceType::AV_HWDEVICE_TYPE_NONE;
	while ((device_type=av_hwdevice_iterate_types(device_type))!= AVHWDeviceType::AV_HWDEVICE_TYPE_NONE)
	{
		spdlog::info("support device {}",av_hwdevice_get_type_name(device_type));
	}
}

void rtsp_uninit()
{
	spdlog::info(__FUNCTION__);
	std::lock_guard<std::mutex> autolock(dll_mutex);
	if (gPreviousFilter)
	{
		SetUnhandledExceptionFilter(gPreviousFilter);
		gPreviousFilter = NULL;
	}
}

void* rtsp_generate(const char* szUrl)
{
	if (szUrl == nullptr)
	{
		spdlog::error(__FUNCTION__" url is nullptr");
		return nullptr;
	}
	CRtspPlay* handle = new (std::nothrow)CRtspPlay(szUrl);
	if (handle == nullptr)
	{
		spdlog::error(__FUNCTION__" 创建对象失败");
		return nullptr;
	}
	spdlog::info(__FUNCTION__" 创建对象成功，返回对象指针地址: {}", (void*)handle);
	return handle;
}

void rtsp_set_encode_cb(void* handle, encode_callback pFunDecodeData)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return;
	}
	phandle->SetEncodeCallBack(pFunDecodeData);
}

void rtsp_set_decode_cb(void* handle, decode_callback pFunDecodeData)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return;
	}
	phandle->SetDecodeCallBack(pFunDecodeData);
}

LIBRTSP_API void rtsp_set_audio_cb(void* handle, audio_callback pFunDecodeData)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return;
	}
	phandle->SetAudioCallBack(pFunDecodeData);
}


int rtsp_release(void** handle)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return -1;
	}
	void* delay_handle = *handle;
	*handle = nullptr;
	std::thread closethread([delay_handle]()
		{
			CRtspPlay* phandle = static_cast<CRtspPlay*> (delay_handle);
			if (phandle == nullptr)
			{
				return;
			}
			spdlog::info(" 开始释放对象:{}", delay_handle);
			phandle->Stop();
			delete phandle;
			phandle = nullptr;
			spdlog::info(" 释放完成 ");
		});
	closethread.detach();
	return 0;
}

int rtsp_start(void* handle)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return -1;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return -2;
	}
	phandle->Start();
	return 0;
}

int rtsp_stop(void* handle)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return -1;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return -2;
	}
	phandle->Stop();
	return 0;
}

LIBRTSP_API int rtsp_getframe(void* handle, char** data, int* len, int* w, int* h, int* type)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return -1;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return -2;
	}
	return phandle->GetFrame(data,len,w,h, type,false);
}

LIBRTSP_API void rtsp_freeframe(char** data)
{
}

LIBRTSP_API int rtsp_getframe_ex(void* handle, char** data, int* len, int* w, int* h, int* type)
{
	if (!handle)
	{
		spdlog::error(__FUNCTION__" 传入对象指针为 null");
		return -1;
	}
	CRtspPlay* phandle = static_cast<CRtspPlay*> (handle);
	if (phandle == nullptr)
	{
		spdlog::error(__FUNCTION__" 指针转化成对象失败，请检查地址: {}", handle);
		return -2;
	}
	return phandle->GetFrame(data, len, w, h, type,true);
}

